"""最小二乘法"""
import numpy as np
import datetime
import time
import tushare as ts
from chinese_calendar import is_holiday
from stockSelect10_soup_phone_1  import getstock
ts.set_token("6667cd4a2326f2f937062a0f4fb59aea5c56d13b1f6f26225f115fe9")
pro = ts.pro_api()
# import matplotlib.pyplot as plt
#https://zhuanlan.zhihu.com/p/38128785/

def fun2ploy(x,n):  #得到范德蒙德（Vandermonde）行列式
    '''
    数据转化为[x^0,x^1,x^2,...x^n]
    首列变1
    '''
    lens = len(x)
    X = np.ones([1,lens])
    for i in range(1,n):
        X = np.vstack((X,np.power(x,i)))#按行堆叠
    #print('Vandermonde行列式:',X)
    return X  

def leastseq_byploy(x,y,ploy_dim):  #https://blog.csdn.net/dz4543/article/details/85224391
    '''
    最小二乘求解
  '''
    X = fun2ploy(x,ploy_dim)
    #直接求解
    Xt = X.transpose();#转置变成列向量 X=[[x^0][x^1][x^2][x^3]]
    XXt=X.dot(Xt);#矩阵乘,X*X^T
    XXtInv = np.linalg.inv(XXt)#求逆 (X*X^T)^-1
    XXtInvX = XXtInv.dot(X) #(X*X^T)^-1*X
    #获得系数列向量
    coef = XXtInvX.dot(y.T)
    y_est = Xt.dot(coef)
    return y_est,coef

def fit_func(p, x):  ## 如 p=numpy.poly1d([1,2,3])  生成  $1x^2+2x^1+3x^0$*,coef 傅立叶展开
    p=p[::-1]
    f = np.poly1d(p)
    return f(x)

def n_days_before(st_day,n):
    """
    st_day:开始日期
    :type st_day: datetime.date | datetime.datetime
    """
    while(n>0):
        if not is_holiday(st_day):
            n=n-1
        st_day=st_day-datetime.timedelta(1)
    return st_day

# 最小二乘拟合
#https://www.cnblogs.com/lc1217/p/6514734.html

symbols=[603113,2938,2876,799,625]
for code in symbols:
    #二阶多项式拟合
    ploy_dim=2
    gs=getstock(code)
    #用7天数据参与预测
    days=7
    #df7=gs.dayN(days)
    end_date_str=time.strftime("%Y%m%d") 
    end_datetime = datetime.datetime.strptime(end_date_str, '%Y%m%d') 
    start_datetime=n_days_before(end_datetime,days) 
    start_date_str=start_datetime.strftime("%Y%m%d") 
    code6=str(code).zfill(6)
    if code6[:2]!="60":
        code_str='{}.SZ'.format(code6)
    else:
        code_str='{}.SH'.format(code6)
    print(code_str)
    df7 = pro.daily(ts_code=code_str, start_date=start_date_str, end_date=end_date_str) 
    df7.set_index('trade_date',inplace=True) 
    df7.sort_index(inplace=True)
    #获7天数据，由远到近
    #print(df7)
    Yh=df7["high"].values
    Yl=df7["low"].values
    Xo=df7["open"].values
    last_close=df7["close"].values[-1]
    # print('Yh',Yh,'\nYl',Yl,'\nXo',Xo,'\nlast_close',last_close)
    #涨停价
    today_high_limit=last_close*1.1
    #跌停价
    today_low_limit=last_close*0.9
    [h_est,h_coef] = leastseq_byploy(Xo,Yh,ploy_dim)
    [l_est,l_coef] = leastseq_byploy(Xo,Yl,ploy_dim)
    err_h=np.sum((fit_func(h_coef,Xo)-Yh)**2)/len(Xo)
    err_l=np.sum((fit_func(l_coef,Xo)-Yl)**2)/len(Xo)
    # print('预测最高价:',np.round(fit_func(h_coef,Xo),2))
    # print('预测最低价:',np.round(fit_func(l_coef,Xo),2))
    # print("high标准差",np.sqrt(err_h))
    # print("low标准差",np.sqrt(err_l))
    #https://baike.baidu.com/item/黑塞矩阵/2248782?fr=aladdin
    xo1=float(gs.open)
    print('今日开盘价:',xo1)
    if fit_func(h_coef,xo1) < today_high_limit:
        print("预估最高价:",fit_func(h_coef,xo1))
    else:
        print("预估最高价:",today_high_limit)
        
    if fit_func(l_coef,xo1) > today_low_limit:
        print("预估最低价:",fit_func(l_coef,xo1))
    else:
        print("预估最低价:",today_low_limit)
    print(" ")
